home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2005 October / PCWOCT05.iso / Software / FromTheMag / XAMPP 1.4.14 / xampp-win32-1.4.14-installer.exe / xampp / php / pear / MDB / mysql.php < prev    next >
PHP Script  |  2004-03-24  |  54KB  |  1,498 lines

  1. <?php
  2. // vim: set et ts=4 sw=4 fdm=marker:
  3. // +----------------------------------------------------------------------+
  4. // | PHP Version 4                                                        |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox,                 |
  7. // | Stig. S. Bakken, Lukas Smith                                         |
  8. // | All rights reserved.                                                 |
  9. // +----------------------------------------------------------------------+
  10. // | MDB is a merge of PEAR DB and Metabases that provides a unified DB   |
  11. // | API as well as database abstraction for PHP applications.            |
  12. // | This LICENSE is in the BSD license style.                            |
  13. // |                                                                      |
  14. // | Redistribution and use in source and binary forms, with or without   |
  15. // | modification, are permitted provided that the following conditions   |
  16. // | are met:                                                             |
  17. // |                                                                      |
  18. // | Redistributions of source code must retain the above copyright       |
  19. // | notice, this list of conditions and the following disclaimer.        |
  20. // |                                                                      |
  21. // | Redistributions in binary form must reproduce the above copyright    |
  22. // | notice, this list of conditions and the following disclaimer in the  |
  23. // | documentation and/or other materials provided with the distribution. |
  24. // |                                                                      |
  25. // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken,    |
  26. // | Lukas Smith nor the names of his contributors may be used to endorse |
  27. // | or promote products derived from this software without specific prior|
  28. // | written permission.                                                  |
  29. // |                                                                      |
  30. // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS  |
  31. // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT    |
  32. // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS    |
  33. // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE      |
  34. // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,          |
  35. // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
  36. // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
  37. // |  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED  |
  38. // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT          |
  39. // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
  40. // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE          |
  41. // | POSSIBILITY OF SUCH DAMAGE.                                          |
  42. // +----------------------------------------------------------------------+
  43. // | Author: Lukas Smith <smith@backendmedia.com>                         |
  44. // +----------------------------------------------------------------------+
  45. //
  46. // $Id: mysql.php,v 1.80.4.8 2004/01/08 13:43:02 lsmith Exp $
  47. //
  48.  
  49. require_once('MDB/Common.php');
  50.  
  51. /**
  52.  * MDB MySQL driver
  53.  *
  54.  * Notes:
  55.  * - The decimal type fields are emulated with integer fields.
  56.  *
  57.  * @package MDB
  58.  * @category Database
  59.  * @author  Lukas Smith <smith@backendmedia.com>
  60.  */
  61. class MDB_mysql extends MDB_Common
  62. {
  63.     // {{{ properties
  64.  
  65.     var $connection = 0;
  66.     var $connected_host;
  67.     var $connected_user;
  68.     var $connected_password;
  69.     var $connected_port;
  70.     var $opened_persistent = '';
  71.  
  72.     var $escape_quotes = "\\";
  73.     var $decimal_factor = 1.0;
  74.  
  75.     var $highest_fetched_row = array();
  76.     var $columns = array();
  77.  
  78.     // MySQL specific class variable
  79.     var $default_table_type = '';
  80.     var $fixed_float = 0;
  81.     var $dummy_primary_key = 'dummy_primary_key';
  82.  
  83.     // }}}
  84.     // {{{ constructor
  85.  
  86.     /**
  87.     * Constructor
  88.     */
  89.     function MDB_mysql()
  90.     {
  91.         $this->MDB_Common();
  92.         $this->phptype = 'mysql';
  93.         $this->dbsyntax = 'mysql';
  94.  
  95.         $this->supported['Sequences'] = 1;
  96.         $this->supported['Indexes'] = 1;
  97.         $this->supported['AffectedRows'] = 1;
  98.         $this->supported['Summaryfunctions'] = 1;
  99.         $this->supported['OrderByText'] = 1;
  100.         $this->supported['CurrId'] = 1;
  101.         $this->supported['SelectRowRanges'] = 1;
  102.         $this->supported['LOBs'] = 1;
  103.         $this->supported['Replace'] = 1;
  104.         $this->supported['SubSelects'] = 0;
  105.         $this->supported['Transactions'] = 0;
  106.         
  107.         $this->decimal_factor = pow(10.0, $this->decimal_places);
  108.         
  109.         $this->options['DefaultTableType'] = FALSE;
  110.         $this->options['fixed_float'] = FALSE;
  111.         
  112.         $this->errorcode_map = array(
  113.             1004 => MDB_ERROR_CANNOT_CREATE,
  114.             1005 => MDB_ERROR_CANNOT_CREATE,
  115.             1006 => MDB_ERROR_CANNOT_CREATE,
  116.             1007 => MDB_ERROR_ALREADY_EXISTS,
  117.             1008 => MDB_ERROR_CANNOT_DROP,
  118.             1022 => MDB_ERROR_ALREADY_EXISTS,
  119.             1046 => MDB_ERROR_NODBSELECTED,
  120.             1050 => MDB_ERROR_ALREADY_EXISTS,
  121.             1051 => MDB_ERROR_NOSUCHTABLE,
  122.             1054 => MDB_ERROR_NOSUCHFIELD,
  123.             1062 => MDB_ERROR_ALREADY_EXISTS,
  124.             1064 => MDB_ERROR_SYNTAX,
  125.             1100 => MDB_ERROR_NOT_LOCKED,
  126.             1136 => MDB_ERROR_VALUE_COUNT_ON_ROW,
  127.             1146 => MDB_ERROR_NOSUCHTABLE,
  128.             1048 => MDB_ERROR_CONSTRAINT,
  129.             1216 => MDB_ERROR_CONSTRAINT,
  130.         );
  131.     }
  132.  
  133.     // }}}
  134.     // {{{ errorNative()
  135.  
  136.     /**
  137.      * Get the native error code of the last error (if any) that
  138.      * occured on the current connection.
  139.      *
  140.      * @access public
  141.      *
  142.      * @return int native MySQL error code
  143.      */
  144.     function errorNative()
  145.     {
  146.         return mysql_errno($this->connection);
  147.     }
  148.  
  149.     // }}}
  150.     // {{{ mysqlRaiseError()
  151.  
  152.     /**
  153.      * This method is used to communicate an error and invoke error
  154.      * callbacks etc.  Basically a wrapper for MDB::raiseError
  155.      * that checks for native error msgs.
  156.      *
  157.      * @param integer $errno error code
  158.      * @return object a PEAR error object
  159.      * @access public
  160.      * @see PEAR_Error
  161.      */
  162.     function mysqlRaiseError($errno = NULL)
  163.     {
  164.         if ($errno == NULL) {
  165.             $errno = $this->errorCode(mysql_errno($this->connection));
  166.         }
  167.         return($this->raiseError($errno, NULL, NULL, NULL, @mysql_error($this->connection)));
  168.     }
  169.  
  170.     // }}}
  171.     // {{{ autoCommit()
  172.  
  173.     /**
  174.      * Define whether database changes done on the database be automatically
  175.      * committed. This function may also implicitly start or end a transaction.
  176.      *
  177.      * @param boolean $auto_commit    flag that indicates whether the database
  178.      *                                changes should be committed right after
  179.      *                                executing every query statement. If this
  180.      *                                argument is 0 a transaction implicitly
  181.      *                                started. Otherwise, if a transaction is
  182.      *                                in progress it is ended by committing any
  183.      *                                database changes that were pending.
  184.      *
  185.      * @access public
  186.      *
  187.      * @return mixed MDB_OK on success, a MDB error on failure
  188.      */
  189.     function autoCommit($auto_commit)
  190.     {
  191.         $this->debug("AutoCommit: ".($auto_commit ? "On" : "Off"));
  192.         if (!isset($this->supported['Transactions'])) {
  193.             return($this->raiseError(MDB_ERROR_UNSUPPORTED, NULL, NULL,
  194.                 'Auto-commit transactions: transactions are not in use'));
  195.         }
  196.         if ($this->auto_commit == $auto_commit) {
  197.             return(MDB_OK);
  198.         }
  199.         if ($this->connection) {
  200.             if ($auto_commit) {
  201.                 $result = $this->query('COMMIT');
  202.                 if (MDB::isError($result)) {
  203.                     return($result);
  204.                 }
  205.                 $result = $this->query('SET AUTOCOMMIT = 1');
  206.                 if (MDB::isError($result)) {
  207.                     return($result);
  208.                 }
  209.             } else {
  210.                 $result = $this->query('SET AUTOCOMMIT = 0');
  211.                 if (MDB::isError($result)) {
  212.                     return($result);
  213.                 }
  214.             }
  215.         }
  216.         $this->auto_commit = $auto_commit;
  217.         $this->in_transaction = !$auto_commit;
  218.         return(MDB_OK);
  219.     }
  220.  
  221.     // }}}
  222.     // {{{ commit()
  223.  
  224.     /**
  225.      * Commit the database changes done during a transaction that is in
  226.      * progress. This function may only be called when auto-committing is
  227.      * disabled, otherwise it will fail. Therefore, a new transaction is
  228.      * implicitly started after committing the pending changes.
  229.      *
  230.      * @access public
  231.      *
  232.      * @return mixed MDB_OK on success, a MDB error on failure
  233.      */
  234.     function commit()
  235.     {
  236.         $this->debug("Commit Transaction");
  237.         if (!isset($this->supported['Transactions'])) {
  238.             return($this->raiseError(MDB_ERROR_UNSUPPORTED, NULL, NULL,
  239.                 'Commit transactions: transactions are not in use'));
  240.         }
  241.         if ($this->auto_commit) {
  242.             return($this->raiseError(MDB_ERROR, NULL, NULL,
  243.             'Commit transactions: transaction changes are being auto commited'));
  244.         }
  245.         return($this->query('COMMIT'));
  246.     }
  247.  
  248.     // }}}
  249.     // {{{ rollback()
  250.  
  251.     /**
  252.      * Cancel any database changes done during a transaction that is in
  253.      * progress. This function may only be called when auto-committing is
  254.      * disabled, otherwise it will fail. Therefore, a new transaction is
  255.      * implicitly started after canceling the pending changes.
  256.      *
  257.      * @access public
  258.      *
  259.      * @return mixed MDB_OK on success, a MDB error on failure
  260.      */
  261.     function rollback()
  262.     {
  263.         $this->debug("Rollback Transaction");
  264.         if (!isset($this->supported['Transactions'])) {
  265.             return($this->raiseError(MDB_ERROR_UNSUPPORTED, NULL, NULL,
  266.                 'Rollback transactions: transactions are not in use'));
  267.         }
  268.         if ($this->auto_commit) {
  269.             return($this->raiseError(MDB_ERROR, NULL, NULL,
  270.                 'Rollback transactions: transactions can not be rolled back when changes are auto commited'));
  271.         }
  272.         return($this->query('ROLLBACK'));
  273.     }
  274.  
  275.     // }}}
  276.     // {{{ connect()
  277.  
  278.     /**
  279.      * Connect to the database
  280.      *
  281.      * @return TRUE on success, MDB_Error on failure
  282.      **/
  283.     function connect()
  284.     {
  285.         $port = (isset($this->port) ? $this->port : '');
  286.         if($this->connection != 0) {
  287.             if (!strcmp($this->connected_host, $this->host)
  288.                 && !strcmp($this->connected_user, $this->user)
  289.                 && !strcmp($this->connected_password, $this->password)
  290.                 && !strcmp($this->connected_port, $port)
  291.                 && $this->opened_persistent == $this->options['persistent'])
  292.             {
  293.                 return(MDB_OK);
  294.             }
  295.             mysql_close($this->connection);
  296.             $this->connection = 0;
  297.             $this->affected_rows = -1;
  298.         }
  299.  
  300.         if(!PEAR::loadExtension($this->phptype)) {
  301.             return(PEAR::raiseError(NULL, MDB_ERROR_NOT_FOUND,
  302.                 NULL, NULL, 'extension '.$this->phptype.' is not compiled into PHP',
  303.                 'MDB_Error', TRUE));
  304.         }
  305.         $UseTransactions = $this->getOption('UseTransactions');
  306.         if(!MDB::isError($UseTransactions) && $UseTransactions) {
  307.             $this->supported['Transactions'] = 1;
  308.             $this->default_table_type = 'BDB';
  309.         } else {
  310.             $this->supported['Transactions'] = 0;
  311.             $this->default_table_type = '';
  312.         }
  313.         $DefaultTableType = $this->getOption('DefaultTableType');
  314.         if(!MDB::isError($DefaultTableType) && $DefaultTableType) {
  315.             switch($this->default_table_type = strtoupper($DefaultTableType)) {
  316.                 case 'BERKELEYDB':
  317.                     $this->default_table_type = 'BDB';
  318.                 case 'BDB':
  319.                 case 'INNODB':
  320.                 case 'GEMINI':
  321.                     break;
  322.                 case 'HEAP':
  323.                 case 'ISAM':
  324.                 case 'MERGE':
  325.                 case 'MRG_MYISAM':
  326.                 case 'MYISAM':
  327.                     if(isset($this->supported['Transactions'])) {
  328.                         $this->warnings[] = $DefaultTableType
  329.                             .' is not a transaction-safe default table type';
  330.                     }
  331.                     break;
  332.                 default:
  333.                     $this->warnings[] = $DefaultTableType
  334.                         .' is not a supported default table type';
  335.             }
  336.         }
  337.  
  338.         $this->fixed_float = 30;
  339.         $function = ($this->options['persistent'] ? 'mysql_pconnect' : 'mysql_connect');
  340.         if (!function_exists($function)) {
  341.             return($this->raiseError(MDB_ERROR_UNSUPPORTED));
  342.         }
  343.  
  344.         @ini_set('track_errors', TRUE);
  345.         $this->connection = @$function(
  346.             $this->host.(!strcmp($port,'') ? '' : ':'.$port),
  347.             $this->user, $this->password);
  348.         @ini_restore('track_errors');
  349.         if ($this->connection <= 0) {
  350.             return($this->raiseError(MDB_ERROR_CONNECT_FAILED, NULL, NULL,
  351.                 $php_errormsg));
  352.         }
  353.  
  354.         if (isset($this->options['fixedfloat'])) {
  355.             $this->fixed_float = $this->options['fixedfloat'];
  356.         } else {
  357.             if (($result = mysql_query('SELECT VERSION()', $this->connection))) {
  358.                 $version = explode('.', mysql_result($result,0,0));
  359.                 $major = intval($version[0]);
  360.                 $minor = intval($version[1]);
  361.                 $revision = intval($version[2]);
  362.                 if ($major > 3 || ($major == 3 && $minor >= 23
  363.                     && ($minor > 23 || $revision >= 6)))
  364.                 {
  365.                     $this->fixed_float = 0;
  366.                 }
  367.                 mysql_free_result($result);
  368.             }
  369.         }
  370.         if (isset($this->supported['Transactions']) && !$this->auto_commit) {
  371.             if (!mysql_query('SET AUTOCOMMIT = 0', $this->connection)) {
  372.                 mysql_close($this->connection);
  373.                 $this->connection = 0;
  374.                 $this->affected_rows = -1;
  375.                 return($this->raiseError());
  376.             }
  377.             $this->in_transaction = TRUE;
  378.         }
  379.         $this->connected_host = $this->host;
  380.         $this->connected_user = $this->user;
  381.         $this->connected_password = $this->password;
  382.         $this->connected_port = $port;
  383.         $this->opened_persistent = $this->getoption('persistent');
  384.         return(MDB_OK);
  385.     }
  386.  
  387.     // }}}
  388.     // {{{ _close()
  389.     /**
  390.      * all the RDBMS specific things needed close a DB connection
  391.      *
  392.      * @return boolean
  393.      * @access private
  394.      **/
  395.     function _close()
  396.     {
  397.         if ($this->connection != 0) {
  398.             if (isset($this->supported['Transactions']) && !$this->auto_commit) {
  399.                 $result = $this->autoCommit(TRUE);
  400.             }
  401.             mysql_close($this->connection);
  402.             $this->connection = 0;
  403.             $this->affected_rows = -1;
  404.  
  405.             if (isset($result) && MDB::isError($result)) {
  406.                 return($result);
  407.             }
  408.             unset($GLOBALS['_MDB_databases'][$this->database]);
  409.             return(TRUE);
  410.         }
  411.         return(FALSE);
  412.     }
  413.  
  414.     // }}}
  415.     // {{{ query()
  416.  
  417.     /**
  418.      * Send a query to the database and return any results
  419.      *
  420.      * @access public
  421.      *
  422.      * @param string  $query  the SQL query
  423.      * @param mixed   $types  array that contains the types of the columns in
  424.      *                        the result set
  425.      *
  426.      * @return mixed a result handle or MDB_OK on success, a MDB error on failure
  427.      */
  428.     function query($query, $types = NULL)
  429.     {
  430.         $this->debug("Query: $query");
  431.         $ismanip = MDB::isManip($query);
  432.         $this->last_query = $query;
  433.         $first = $this->first_selected_row;
  434.         $limit = $this->selected_row_limit;
  435.         $this->first_selected_row = $this->selected_row_limit = 0;
  436.  
  437.         $result = $this->connect();
  438.         if (MDB::isError($result)) {
  439.             return($result);
  440.         }
  441.         if($limit > 0) {
  442.             if ($ismanip) {
  443.                 $query .= " LIMIT $limit";
  444.             } else {
  445.                 $query .= " LIMIT $first,$limit";
  446.             }
  447.         }
  448.         if ($this->database_name) {
  449.             if(!mysql_select_db($this->database_name, $this->connection)) {
  450.                 return($this->mysqlRaiseError());
  451.             }
  452.         }
  453.         if ($result = mysql_query($query, $this->connection)) {
  454.             if ($ismanip) {
  455.                 $this->affected_rows = mysql_affected_rows($this->connection);
  456.                 return(MDB_OK);
  457.             } else {
  458.                 $this->highest_fetched_row[$result] = -1;
  459.                 if ($types != NULL) {
  460.                     if (!is_array($types)) {
  461.                         $types = array($types);
  462.                     }
  463.                     if (MDB::isError($err = $this->setResultTypes($result, $types))) {
  464.                         $this->freeResult($result);
  465.                         return($err);
  466.                     }
  467.                 }
  468.                 return($result);
  469.             }
  470.         }
  471.         return($this->mysqlRaiseError());
  472.     }
  473.  
  474.     // }}}
  475.     // {{{ subSelect()
  476.  
  477.     /**
  478.      * simple subselect emulation for Mysql
  479.      *
  480.      * @access public
  481.      *
  482.      * @param string $query the SQL query for the subselect that may only
  483.      *                      return a column
  484.      * @param string $quote determines if the data needs to be quoted before
  485.      *                      being returned
  486.      *
  487.      * @return string the query
  488.      */
  489.     function subSelect($query, $quote = FALSE)
  490.     {
  491.         if($this->supported['SubSelects'] == 1) {
  492.             return($query);
  493.         }
  494.         $col = $this->queryCol($query);
  495.         if (MDB::isError($col)) {
  496.             return($col);
  497.         }
  498.         if(!is_array($col) || count($col) == 0) {
  499.             return 'NULL';
  500.         }
  501.         if($quote) {
  502.             for($i = 0, $j = count($col); $i < $j; ++$i) {
  503.                 $col[$i] = $this->getTextValue($col[$i]);
  504.             }
  505.         }
  506.         return(implode(', ', $col));
  507.     }
  508.  
  509.     // }}}
  510.     // {{{ replace()
  511.  
  512.     /**
  513.      * Execute a SQL REPLACE query. A REPLACE query is identical to a INSERT
  514.      * query, except that if there is already a row in the table with the same
  515.      * key field values, the REPLACE query just updates its values instead of
  516.      * inserting a new row.
  517.      *
  518.      * The REPLACE type of query does not make part of the SQL standards. Since
  519.      * practically only MySQL implements it natively, this type of query is
  520.      * emulated through this method for other DBMS using standard types of
  521.      * queries inside a transaction to assure the atomicity of the operation.
  522.      *
  523.      * @access public
  524.      *
  525.      * @param string $table name of the table on which the REPLACE query will
  526.      *  be executed.
  527.      * @param array $fields associative array that describes the fields and the
  528.      *  values that will be inserted or updated in the specified table. The
  529.      *  indexes of the array are the names of all the fields of the table. The
  530.      *  values of the array are also associative arrays that describe the
  531.      *  values and other properties of the table fields.
  532.      *
  533.      *  Here follows a list of field properties that need to be specified:
  534.      *
  535.      *    Value:
  536.      *          Value to be assigned to the specified field. This value may be
  537.      *          of specified in database independent type format as this
  538.      *          function can perform the necessary datatype conversions.
  539.      *
  540.      *    Default:
  541.      *          this property is required unless the Null property
  542.      *          is set to 1.
  543.      *
  544.      *    Type
  545.      *          Name of the type of the field. Currently, all types Metabase
  546.      *          are supported except for clob and blob.
  547.      *
  548.      *    Default: no type conversion
  549.      *
  550.      *    Null
  551.      *          Boolean property that indicates that the value for this field
  552.      *          should be set to NULL.
  553.      *
  554.      *          The default value for fields missing in INSERT queries may be
  555.      *          specified the definition of a table. Often, the default value
  556.      *          is already NULL, but since the REPLACE may be emulated using
  557.      *          an UPDATE query, make sure that all fields of the table are
  558.      *          listed in this function argument array.
  559.      *
  560.      *    Default: 0
  561.      *
  562.      *    Key
  563.      *          Boolean property that indicates that this field should be
  564.      *          handled as a primary key or at least as part of the compound
  565.      *          unique index of the table that will determine the row that will
  566.      *          updated if it exists or inserted a new row otherwise.
  567.      *
  568.      *          This function will fail if no key field is specified or if the
  569.      *          value of a key field is set to NULL because fields that are
  570.      *          part of unique index they may not be NULL.
  571.      *
  572.      *    Default: 0
  573.      *
  574.      * @return mixed MDB_OK on success, a MDB error on failure
  575.      */
  576.     function replace($table, $fields)
  577.     {
  578.         $count = count($fields);
  579.         for($keys = 0, $query = $values = '',reset($fields), $field = 0;
  580.             $field<$count;
  581.             next($fields), $field++)
  582.         {
  583.             $name = key($fields);
  584.             if ($field > 0) {
  585.                 $query .= ',';
  586.                 $values .= ',';
  587.             }
  588.             $query .= $name;
  589.             if (isset($fields[$name]['Null']) && $fields[$name]['Null']) {
  590.                 $value = 'NULL';
  591.             } else {
  592.                 if(isset($fields[$name]['Type'])) {
  593.                     switch ($fields[$name]['Type']) {
  594.                         case 'text':
  595.                             $value = $this->getTextValue($fields[$name]['Value']);
  596.                             break;
  597.                         case 'boolean':
  598.                             $value = $this->getBooleanValue($fields[$name]['Value']);
  599.                             break;
  600.                         case 'integer':
  601.                             $value = $this->getIntegerValue($fields[$name]['Value']);
  602.                             break;
  603.                         case 'decimal':
  604.                             $value = $this->getDecimalValue($fields[$name]['Value']);
  605.                             break;
  606.                         case 'float':
  607.                             $value = $this->getFloatValue($fields[$name]['Value']);
  608.                             break;
  609.                         case 'date':
  610.                             $value = $this->getDateValue($fields[$name]['Value']);
  611.                             break;
  612.                         case 'time':
  613.                             $value = $this->getTimeValue($fields[$name]['Value']);
  614.                             break;
  615.                         case 'timestamp':
  616.                             $value = $this->getTimestampValue($fields[$name]['Value']);
  617.                             break;
  618.                         default:
  619.                             return($this->raiseError(MDB_ERROR_CANNOT_REPLACE, NULL, NULL,
  620.                                 'no supported type for field "' . $name . '" specified'));
  621.                     }
  622.                 } else {
  623.                     $value = $fields[$name]['Value'];
  624.                 }
  625.             }
  626.             $values .= $value;
  627.             if (isset($fields[$name]['Key']) && $fields[$name]['Key']) {
  628.                 if ($value === 'NULL') {
  629.                     return($this->raiseError(MDB_ERROR_CANNOT_REPLACE, NULL, NULL,
  630.                         $name.': key values may not be NULL'));
  631.                 }
  632.                 $keys++;
  633.             }
  634.         }
  635.         if ($keys == 0) {
  636.             return($this->raiseError(MDB_ERROR_CANNOT_REPLACE, NULL, NULL,
  637.                 'not specified which fields are keys'));
  638.         }
  639.         return($this->query("REPLACE INTO $table ($query) VALUES ($values)"));
  640.     }
  641.  
  642.     // }}}
  643.     // {{{ getColumnNames()
  644.  
  645.     /**
  646.      * Retrieve the names of columns returned by the DBMS in a query result.
  647.      *
  648.      * @param resource   $result    result identifier
  649.      * @return mixed                an associative array variable
  650.      *                              that will hold the names of columns. The
  651.      *                              indexes of the array are the column names
  652.      *                              mapped to lower case and the values are the
  653.      *                              respective numbers of the columns starting
  654.      *                              from 0. Some DBMS may not return any
  655.      *                              columns when the result set does not
  656.      *                              contain any rows.
  657.      *
  658.      *                              a MDB error on failure
  659.      * @access public
  660.      */
  661.     function getColumnNames($result)
  662.     {
  663.         $result_value = intval($result);
  664.         if (!isset($this->highest_fetched_row[$result_value])) {
  665.             return($this->raiseError(MDB_ERROR_INVALID, NULL, NULL,
  666.                 'Get column names: it was specified an inexisting result set'));
  667.         }
  668.         if (!isset($this->columns[$result_value])) {
  669.             $this->columns[$result_value] = array();
  670.             $columns = mysql_num_fields($result);
  671.             for($column = 0; $column < $columns; $column++) {
  672.                 $this->columns[$result_value][strtolower(mysql_field_name($result, $column))] = $column;
  673.             }
  674.         }
  675.         return($this->columns[$result_value]);
  676.     }
  677.  
  678.     // }}}
  679.     // {{{ numCols()
  680.  
  681.     /**
  682.      * Count the number of columns returned by the DBMS in a query result.
  683.      *
  684.      * @param resource    $result        result identifier
  685.      * @access public
  686.      * @return mixed integer value with the number of columns, a MDB error
  687.      *                       on failure
  688.      */
  689.     function numCols($result)
  690.     {
  691.         if (!isset($this->highest_fetched_row[intval($result)])) {
  692.             return($this->raiseError(MDB_ERROR_INVALID, NULL, NULL,
  693.                 'numCols: it was specified an inexisting result set'));
  694.         }
  695.         return(mysql_num_fields($result));
  696.     }
  697.  
  698.     // }}}
  699.     // {{{ endOfResult()
  700.  
  701.     /**
  702.     * check if the end of the result set has been reached
  703.     *
  704.     * @param resource    $result result identifier
  705.     * @return mixed TRUE or FALSE on sucess, a MDB error on failure
  706.     * @access public
  707.     */
  708.     function endOfResult($result)
  709.     {
  710.         if (!isset($this->highest_fetched_row[$result])) {
  711.             return($this->raiseError(MDB_ERROR, NULL, NULL,
  712.                 'End of result: attempted to check the end of an unknown result'));
  713.         }
  714.         return($this->highest_fetched_row[$result] >= $this->numRows($result)-1);
  715.     }
  716.  
  717.     // }}}
  718.     // {{{ fetch()
  719.  
  720.     /**
  721.     * fetch value from a result set
  722.     *
  723.     * @param resource    $result result identifier
  724.     * @param int    $row    number of the row where the data can be found
  725.     * @param int    $field    field number where the data can be found
  726.     * @return mixed string on success, a MDB error on failure
  727.     * @access public
  728.     */
  729.     function fetch($result, $row, $field)
  730.     {
  731.         $this->highest_fetched_row[$result] =
  732.             max($this->highest_fetched_row[$result], $row);
  733.         $res = @mysql_result($result, $row, $field);
  734.         if ($res === FALSE && $res != NULL) {
  735.             return($this->mysqlRaiseError($errno));
  736.         }
  737.         return($res);
  738.     }
  739.  
  740.     // }}}
  741.     // {{{ fetchClob()
  742.  
  743.     /**
  744.     * fetch a clob value from a result set
  745.     *
  746.     * @param resource    $result result identifier
  747.     * @param int    $row    number of the row where the data can be found
  748.     * @param int    $field    field number where the data can be found
  749.     * @return mixed content of the specified data cell, a MDB error on failure,
  750.     *               a MDB error on failure
  751.     * @access public
  752.     */
  753.     function fetchClob($result, $row, $field)
  754.     {
  755.         return($this->fetchLob($result, $row, $field));
  756.     }
  757.  
  758.     // }}}
  759.     // {{{ fetchBlob()
  760.  
  761.     /**
  762.     * fetch a blob value from a result set
  763.     *
  764.     * @param resource    $result result identifier
  765.     * @param int    $row    number of the row where the data can be found
  766.     * @param int    $field    field number where the data can be found
  767.     * @return mixed content of the specified data cell, a MDB error on failure
  768.     * @access public
  769.     */
  770.     function fetchBlob($result, $row, $field)
  771.     {
  772.         return($this->fetchLob($result, $row, $field));
  773.     }
  774.  
  775.     // }}}
  776.     // {{{ convertResult()
  777.  
  778.     /**
  779.     * convert a value to a RDBMS indepdenant MDB type
  780.     *
  781.     * @param mixed  $value   value to be converted
  782.     * @param int    $type    constant that specifies which type to convert to
  783.     * @return mixed converted value
  784.     * @access public
  785.     */
  786.     function convertResult($value, $type)
  787.     {
  788.         switch($type) {
  789.             case MDB_TYPE_DECIMAL:
  790.                 return(sprintf('%.'.$this->decimal_places.'f', doubleval($value)/$this->decimal_factor));
  791.             default:
  792.                 return($this->_baseConvertResult($value, $type));
  793.         }
  794.     }
  795.  
  796.     // }}}
  797.     // {{{ numRows()
  798.  
  799.     /**
  800.     * returns the number of rows in a result object
  801.     *
  802.      * @param ressource $result a valid result ressouce pointer
  803.     * @return mixed MDB_Error or the number of rows
  804.     * @access public
  805.     */
  806.     function numRows($result)
  807.     {
  808.         return(mysql_num_rows($result));
  809.     }
  810.  
  811.     // }}}
  812.     // {{{ freeResult()
  813.  
  814.     /**
  815.      * Free the internal resources associated with $result.
  816.      *
  817.      * @param $result result identifier
  818.      * @return boolean TRUE on success, FALSE if $result is invalid
  819.      * @access public
  820.      */
  821.     function freeResult($result)
  822.     {
  823.         if(isset($this->highest_fetched_row[$result])) {
  824.             unset($this->highest_fetched_row[$result]);
  825.         }
  826.         if(isset($this->columns[$result])) {
  827.             unset($this->columns[$result]);
  828.         }
  829.         if(isset($this->result_types[$result])) {
  830.             unset($this->result_types[$result]);
  831.         }
  832.         return(mysql_free_result($result));
  833.     }
  834.  
  835.     // }}}
  836.     // {{{ getIntegerDeclaration()
  837.  
  838.     /**
  839.      * Obtain DBMS specific SQL code portion needed to declare an integer type
  840.      * field to be used in statements like CREATE TABLE.
  841.      *
  842.      * @param string  $name   name the field to be declared.
  843.      * @param string  $field  associative array with the name of the properties
  844.      *                        of the field being declared as array indexes.
  845.      *                        Currently, the types of supported field
  846.      *                        properties are as follows:
  847.      *
  848.      *                       unsigned
  849.      *                        Boolean flag that indicates whether the field
  850.      *                        should be declared as unsigned integer if
  851.      *                        possible.
  852.      *
  853.      *                       default
  854.      *                        Integer value to be used as default for this
  855.      *                        field.
  856.      *
  857.      *                       notnull
  858.      *                        Boolean flag that indicates whether this field is
  859.      *                        constrained to not be set to NULL.
  860.      * @return string  DBMS specific SQL code portion that should be used to
  861.      *                 declare the specified field.
  862.      * @access public
  863.      */
  864.     function getIntegerDeclaration($name, $field)
  865.     {
  866.         return("$name INT".
  867.                 (isset($field['unsigned']) ? ' UNSIGNED' : '').
  868.                 (isset($field['default']) ? ' DEFAULT '.$field['default'] : '').
  869.                 (isset($field['notnull']) ? ' NOT NULL' : '')
  870.                );
  871.     }
  872.  
  873.     // }}}
  874.     // {{{ getClobDeclaration()
  875.  
  876.     /**
  877.      * Obtain DBMS specific SQL code portion needed to declare an character
  878.      * large object type field to be used in statements like CREATE TABLE.
  879.      *
  880.      * @param string  $name   name the field to be declared.
  881.      * @param string  $field  associative array with the name of the
  882.      *                        properties of the field being declared as array
  883.      *                        indexes. Currently, the types of supported field
  884.      *                        properties are as follows:
  885.      *
  886.      *                       length
  887.      *                        Integer value that determines the maximum length
  888.      *                        of the large object field. If this argument is
  889.      *                        missing the field should be declared to have the
  890.      *                        longest length allowed by the DBMS.
  891.      *
  892.      *                       notnull
  893.      *                        Boolean flag that indicates whether this field
  894.      *                        is constrained to not be set to NULL.
  895.      * @return string  DBMS specific SQL code portion that should be used to
  896.      *                 declare the specified field.
  897.      * @access public
  898.      */
  899.     function getClobDeclaration($name, $field)
  900.     {
  901.         if (isset($field['length'])) {
  902.             $length = $field['length'];
  903.             if ($length <= 255) {
  904.                 $type = 'TINYTEXT';
  905.             } else {
  906.                 if ($length <= 65535) {
  907.                     $type = 'TEXT';
  908.                 } else {
  909.                     if ($length <= 16777215) {
  910.                         $type = 'MEDIUMTEXT';
  911.                     } else {
  912.                         $type = 'LONGTEXT';
  913.                     }
  914.                 }
  915.             }
  916.         } else {
  917.             $type = 'LONGTEXT';
  918.         }
  919.         return("$name $type".
  920.                  (isset($field['notnull']) ? ' NOT NULL' : ''));
  921.     }
  922.  
  923.     // }}}
  924.     // {{{ getBlobDeclaration()
  925.  
  926.     /**
  927.      * Obtain DBMS specific SQL code portion needed to declare an binary large
  928.      * object type field to be used in statements like CREATE TABLE.
  929.      *
  930.      * @param string  $name   name the field to be declared.
  931.      * @param string  $field  associative array with the name of the properties
  932.      *                        of the field being declared as array indexes.
  933.      *                        Currently, the types of supported field
  934.      *                        properties are as follows:
  935.      *
  936.      *                       length
  937.      *                        Integer value that determines the maximum length
  938.      *                        of the large object field. If this argument is
  939.      *                        missing the field should be declared to have the
  940.      *                        longest length allowed by the DBMS.
  941.      *
  942.      *                       notnull
  943.      *                        Boolean flag that indicates whether this field is
  944.      *                        constrained to not be set to NULL.
  945.      * @return string  DBMS specific SQL code portion that should be used to
  946.      *                 declare the specified field.
  947.      * @access public
  948.      */
  949.     function getBlobDeclaration($name, $field)
  950.     {
  951.         if (isset($field['length'])) {
  952.             $length = $field['length'];
  953.             if ($length <= 255) {
  954.                 $type = 'TINYBLOB';
  955.             } else {
  956.                 if ($length <= 65535) {
  957.                     $type = 'BLOB';
  958.                 } else {
  959.                     if ($length <= 16777215) {
  960.                         $type = 'MEDIUMBLOB';
  961.                     } else {
  962.                         $type = 'LONGBLOB';
  963.                     }
  964.                 }
  965.             }
  966.         }
  967.         else {
  968.             $type = 'LONGBLOB';
  969.         }
  970.         return("$name $type".
  971.                 (isset($field['notnull']) ? ' NOT NULL' : ''));
  972.     }
  973.  
  974.     // }}}
  975.     // {{{ getDateDeclaration()
  976.  
  977.     /**
  978.      * Obtain DBMS specific SQL code portion needed to declare an date type
  979.      * field to be used in statements like CREATE TABLE.
  980.      *
  981.      * @param string  $name   name the field to be declared.
  982.      * @param string  $field  associative array with the name of the properties
  983.      *                        of the field being declared as array indexes.
  984.      *                        Currently, the types of supported field properties
  985.      *                        are as follows:
  986.      *
  987.      *                       default
  988.      *                        Date value to be used as default for this field.
  989.      *
  990.      *                       notnull
  991.      *                        Boolean flag that indicates whether this field is
  992.      *                        constrained to not be set to NULL.
  993.      * @return string  DBMS specific SQL code portion that should be used to
  994.      *                 declare the specified field.
  995.      * @access public
  996.      */
  997.     function getDateDeclaration($name, $field)
  998.     {
  999.         return("$name DATE".
  1000.                 (isset($field['default']) ? " DEFAULT '".$field['default']."'" : '').
  1001.                 (isset($field['notnull']) ? ' NOT NULL' : '')
  1002.                );
  1003.     }
  1004.  
  1005.     // }}}
  1006.     // {{{ getTimestampDeclaration()
  1007.  
  1008.     /**
  1009.      * Obtain DBMS specific SQL code portion needed to declare an timestamp
  1010.      * type field to be used in statements like CREATE TABLE.
  1011.      *
  1012.      * @param string  $name   name the field to be declared.
  1013.      * @param string  $field  associative array with the name of the properties
  1014.      *                        of the field being declared as array indexes.
  1015.      *                        Currently, the types of supported field
  1016.      *                        properties are as follows:
  1017.      *
  1018.      *                       default
  1019.      *                        Time stamp value to be used as default for this
  1020.      *                        field.
  1021.      *
  1022.      *                       notnull
  1023.      *                        Boolean flag that indicates whether this field is
  1024.      *                        constrained to not be set to NULL.
  1025.      * @return string  DBMS specific SQL code portion that should be used to
  1026.      *                 declare the specified field.
  1027.      * @access public
  1028.      */
  1029.     function getTimestampDeclaration($name, $field)
  1030.     {
  1031.         return("$name DATETIME".
  1032.                 (isset($field['default']) ? " DEFAULT '".$field['default']."'" : '').
  1033.                 (isset($field['notnull']) ? ' NOT NULL' : '')
  1034.                );
  1035.     }
  1036.  
  1037.     // }}}
  1038.     // {{{ getTimeDeclaration()
  1039.  
  1040.     /**
  1041.      * Obtain DBMS specific SQL code portion needed to declare an time type
  1042.      * field to be used in statements like CREATE TABLE.
  1043.      *
  1044.      * @param string  $name   name the field to be declared.
  1045.      * @param string  $field  associative array with the name of the properties
  1046.      *                        of the field being declared as array indexes.
  1047.      *                        Currently, the types of supported field
  1048.      *                        properties are as follows:
  1049.      *
  1050.      *                       default
  1051.      *                        Time value to be used as default for this field.
  1052.      *
  1053.      *                       notnull
  1054.      *                        Boolean flag that indicates whether this field is
  1055.      *                        constrained to not be set to NULL.
  1056.      * @return string  DBMS specific SQL code portion that should be used to
  1057.      *                 declare the specified field.
  1058.      * @access public
  1059.      */
  1060.     function getTimeDeclaration($name, $field)
  1061.     {
  1062.         return("$name TIME".
  1063.                 (isset($field['default']) ? " DEFAULT '".$field['default']."'" : '').
  1064.                 (isset($field['notnull']) ? ' NOT NULL' : '')
  1065.                );
  1066.     }
  1067.  
  1068.     // }}}
  1069.     // {{{ getFloatDeclaration()
  1070.  
  1071.     /**
  1072.      * Obtain DBMS specific SQL code portion needed to declare an float type
  1073.      * field to be used in statements like CREATE TABLE.
  1074.      *
  1075.      * @param string  $name   name the field to be declared.
  1076.      * @param string  $field  associative array with the name of the properties
  1077.      *                        of the field being declared as array indexes.
  1078.      *                        Currently, the types of supported field
  1079.      *                        properties are as follows:
  1080.      *
  1081.      *                       default
  1082.      *                        Integer value to be used as default for this
  1083.      *                        field.
  1084.      *
  1085.      *                       notnull
  1086.      *                        Boolean flag that indicates whether this field is
  1087.      *                        constrained to not be set to NULL.
  1088.      * @return string  DBMS specific SQL code portion that should be used to
  1089.      *                 declare the specified field.
  1090.      * @access public
  1091.      */
  1092.     function getFloatDeclaration($name, $field)
  1093.     {
  1094.         if (isset($this->options['fixedfloat'])) {
  1095.             $this->fixed_float = $this->options['fixedfloat'];
  1096.         } else {
  1097.             if ($this->connection == 0) {
  1098.                 // XXX needs more checking
  1099.                 $this->connect();
  1100.             }
  1101.         }
  1102.         return("$name DOUBLE".
  1103.                 ($this->fixed_float ?
  1104.                  '('.($this->fixed_float + 2).','.$this->fixed_float.')' : '').
  1105.                 (isset($field['default']) ?
  1106.                  ' DEFAULT '.$this->getFloatValue($field['default']) : '').
  1107.                 (isset($field['notnull']) ? ' NOT NULL' : '')
  1108.                );
  1109.     }
  1110.  
  1111.     // }}}
  1112.     // {{{ getDecimalDeclaration()
  1113.  
  1114.     /**
  1115.      * Obtain DBMS specific SQL code portion needed to declare an decimal type
  1116.      * field to be used in statements like CREATE TABLE.
  1117.      *
  1118.      * @param string  $name   name the field to be declared.
  1119.      * @param string  $field  associative array with the name of the properties
  1120.      *                        of the field being declared as array indexes.
  1121.      *                        Currently, the types of supported field
  1122.      *                        properties are as follows:
  1123.      *
  1124.      *                       default
  1125.      *                        Integer value to be used as default for this
  1126.      *                        field.
  1127.      *
  1128.      *                       notnull
  1129.      *                        Boolean flag that indicates whether this field is
  1130.      *                        constrained to not be set to NULL.
  1131.      * @return string  DBMS specific SQL code portion that should be used to
  1132.      *                 declare the specified field.
  1133.      * @access public
  1134.      */
  1135.     function getDecimalDeclaration($name, $field)
  1136.     {
  1137.         return("$name BIGINT".
  1138.                 (isset($field['default']) ?
  1139.                  ' DEFAULT '.$this->getDecimalValue($field['default']) : '').
  1140.                  (isset($field['notnull']) ? ' NOT NULL' : '')
  1141.                );
  1142.     }
  1143.  
  1144.     // }}}
  1145.     // {{{ getClobValue()
  1146.  
  1147.     /**
  1148.      * Convert a text value into a DBMS specific format that is suitable to
  1149.      * compose query statements.
  1150.      *
  1151.      * @param resource  $prepared_query query handle from prepare()
  1152.      * @param           $parameter
  1153.      * @param           $clob
  1154.      * @return string  text string that represents the given argument value in
  1155.      *                 a DBMS specific format.
  1156.      * @access public
  1157.      */
  1158.     function getClobValue($prepared_query, $parameter, $clob)
  1159.     {
  1160.         $value = "'";
  1161.         while(!$this->endOfLob($clob)) {
  1162.             if (MDB::isError($result = $this->readLob($clob, $data, $this->options['lob_buffer_length']))) {
  1163.                 return($result);
  1164.             }
  1165.             $value .= $this->_quote($data);
  1166.         }
  1167.         $value .= "'";
  1168.         return($value);
  1169.     }
  1170.  
  1171.     // }}}
  1172.     // {{{ freeClobValue()
  1173.  
  1174.     /**
  1175.      * free a character large object
  1176.      *
  1177.      * @param resource  $prepared_query query handle from prepare()
  1178.      * @param string    $clob
  1179.      * @return MDB_OK
  1180.      * @access public
  1181.      */
  1182.     function freeClobValue($prepared_query, $clob)
  1183.     {
  1184.         unset($this->lobs[$clob]);
  1185.         return(MDB_OK);
  1186.     }
  1187.  
  1188.     // }}}
  1189.     // {{{ getBlobValue()
  1190.  
  1191.     /**
  1192.      * Convert a text value into a DBMS specific format that is suitable to
  1193.      * compose query statements.
  1194.      *
  1195.      * @param resource  $prepared_query query handle from prepare()
  1196.      * @param           $parameter
  1197.      * @param           $blob
  1198.      * @return string  text string that represents the given argument value in
  1199.      *                 a DBMS specific format.
  1200.      * @access public
  1201.      */
  1202.     function getBlobValue($prepared_query, $parameter, $blob)
  1203.     {
  1204.         $value = "'";
  1205.         while(!$this->endOfLob($blob)) {
  1206.             if (MDB::isError($result = $this->readLob($blob, $data, $this->options['lob_buffer_length']))) {
  1207.                 return($result);
  1208.             }
  1209.             $value .= addslashes($data);
  1210.         }
  1211.         $value .= "'";
  1212.         return($value);
  1213.     }
  1214.  
  1215.     // }}}
  1216.     // {{{ freeBlobValue()
  1217.  
  1218.     /**
  1219.      * free a binary large object
  1220.      *
  1221.      * @param resource  $prepared_query query handle from prepare()
  1222.      * @param string    $blob
  1223.      * @return MDB_OK
  1224.      * @access public
  1225.      */
  1226.     function freeBlobValue($prepared_query, $blob)
  1227.     {
  1228.         unset($this->lobs[$blob]);
  1229.         return(MDB_OK);
  1230.     }
  1231.  
  1232.     // }}}
  1233.     // {{{ getFloatValue()
  1234.  
  1235.     /**
  1236.      * Convert a text value into a DBMS specific format that is suitable to
  1237.      * compose query statements.
  1238.      *
  1239.      * @param string  $value text string value that is intended to be converted.
  1240.      * @return string  text string that represents the given argument value in
  1241.      *                 a DBMS specific format.
  1242.      * @access public
  1243.      */
  1244.     function getFloatValue($value)
  1245.     {
  1246.         return(($value === NULL) ? 'NULL' : (float)$value);
  1247.     }
  1248.  
  1249.     // }}}
  1250.     // {{{ getDecimalValue()
  1251.  
  1252.     /**
  1253.      * Convert a text value into a DBMS specific format that is suitable to
  1254.      * compose query statements.
  1255.      *
  1256.      * @param string  $value text string value that is intended to be converted.
  1257.      * @return string  text string that represents the given argument value in
  1258.      *                 a DBMS specific format.
  1259.      * @access public
  1260.      */
  1261.     function getDecimalValue($value)
  1262.     {
  1263.         return(($value === NULL) ? 'NULL' : strval(round(doubleval($value)*$this->decimal_factor)));
  1264.     }
  1265.  
  1266.     // }}}
  1267.     // {{{ nextId()
  1268.  
  1269.     /**
  1270.      * returns the next free id of a sequence
  1271.      *
  1272.      * @param string  $seq_name name of the sequence
  1273.      * @param boolean $ondemand when true the seqence is
  1274.      *                          automatic created, if it
  1275.      *                          not exists
  1276.      *
  1277.      * @return mixed MDB_Error or id
  1278.      * @access public
  1279.      */
  1280.     function nextId($seq_name, $ondemand = TRUE)
  1281.     {
  1282.         $sequence_name = $this->getSequenceName($seq_name);
  1283.         $this->expectError(MDB_ERROR_NOSUCHTABLE);
  1284.         $result = $this->query("INSERT INTO $sequence_name (sequence) VALUES (NULL)");
  1285.         $this->popExpect();
  1286.         if ($ondemand && MDB::isError($result) &&
  1287.             $result->getCode() == MDB_ERROR_NOSUCHTABLE)
  1288.         {
  1289.             // Since we are create the sequence on demand
  1290.             // we know the first id = 1 so initialize the
  1291.             // sequence at 2
  1292.             $result = $this->createSequence($seq_name, 2);
  1293.             if (MDB::isError($result)) {
  1294.                 return($this->raiseError(MDB_ERROR, NULL, NULL,
  1295.                     'Next ID: on demand sequence could not be created'));
  1296.             } else {
  1297.                 // First ID of a newly created sequence is 1
  1298.                 return(1);
  1299.             }
  1300.         }
  1301.         $value = intval(mysql_insert_id($this->connection));
  1302.         $res = $this->query("DELETE FROM $sequence_name WHERE sequence < $value");
  1303.         if (MDB::isError($res)) {
  1304.             $this->warnings[] = 'Next ID: could not delete previous sequence table values';
  1305.         }
  1306.         return($value);
  1307.     }
  1308.  
  1309.  
  1310.     // }}}
  1311.     // {{{ currId()
  1312.  
  1313.     /**
  1314.      * returns the current id of a sequence
  1315.      *
  1316.      * @param string  $seq_name name of the sequence
  1317.      * @return mixed MDB_Error or id
  1318.      * @access public
  1319.      */
  1320.     function currId($seq_name)
  1321.     {
  1322.         $sequence_name = $this->getSequenceName($seq_name);
  1323.         $result = $this->query("SELECT MAX(sequence) FROM $sequence_name", 'integer');
  1324.         if (MDB::isError($result)) {
  1325.             return($result);
  1326.         }
  1327.  
  1328.         return($this->fetchOne($result));
  1329.     }
  1330.  
  1331.     // }}}
  1332.     // {{{ fetchInto()
  1333.  
  1334.     /**
  1335.      * Fetch a row and insert the data into an existing array.
  1336.      *
  1337.      * @param resource  $result     result identifier
  1338.      * @param int       $fetchmode  how the array data should be indexed
  1339.      * @param int       $rownum     the row number to fetch
  1340.      * @return int data array on success, a MDB error on failure
  1341.      * @access public
  1342.      */
  1343.     function fetchInto($result, $fetchmode = MDB_FETCHMODE_DEFAULT, $rownum = NULL)
  1344.     {
  1345.         if ($rownum == NULL) {
  1346.             ++$this->highest_fetched_row[$result];
  1347.         } else {
  1348.             if (!@mysql_data_seek($result, $rownum)) {
  1349.                 return(NULL);
  1350.             }
  1351.             $this->highest_fetched_row[$result] =
  1352.                 max($this->highest_fetched_row[$result], $rownum);
  1353.         }
  1354.         if ($fetchmode == MDB_FETCHMODE_DEFAULT) {
  1355.             $fetchmode = $this->fetchmode;
  1356.         }
  1357.         if ($fetchmode & MDB_FETCHMODE_ASSOC) {
  1358.             $row = @mysql_fetch_assoc($result);
  1359.             if (is_array($row) && $this->options['optimize'] == 'portability') {
  1360.                 $row = array_change_key_case($row, CASE_LOWER);
  1361.             }
  1362.         } else {
  1363.             $row = @mysql_fetch_row($result);
  1364.         }
  1365.         if (!$row) {
  1366.             if($this->options['autofree']) {
  1367.                 $this->freeResult($result);
  1368.             }
  1369.             return(NULL);
  1370.         }
  1371.         if (isset($this->result_types[$result])) {
  1372.             $row = $this->convertResultRow($result, $row);
  1373.         }
  1374.         return($row);
  1375.     }
  1376.  
  1377.     // }}}
  1378.     // {{{ nextResult()
  1379.  
  1380.     /**
  1381.      * Move the internal mysql result pointer to the next available result
  1382.      * Currently not supported
  1383.      *
  1384.      * @param a valid result resource
  1385.      * @return true if a result is available otherwise return false
  1386.      * @access public
  1387.      */
  1388.     function nextResult($result)
  1389.     {
  1390.         return(FALSE);
  1391.     }
  1392.  
  1393.     // }}}
  1394.     // {{{ tableInfo()
  1395.  
  1396.     /**
  1397.     * returns meta data about the result set
  1398.     *
  1399.     * @param resource    $result    result identifier
  1400.     * @param mixed $mode depends on implementation
  1401.     * @return array an nested array, or a MDB error
  1402.     * @access public
  1403.     */
  1404.     function tableInfo($result, $mode = NULL) {
  1405.         $count = 0;
  1406.         $id     = 0;
  1407.         $res  = array();
  1408.  
  1409.         /*
  1410.          * depending on $mode, metadata returns the following values:
  1411.          *
  1412.          * - mode is false (default):
  1413.          * $result[]:
  1414.          *   [0]['table']  table name
  1415.          *   [0]['name']   field name
  1416.          *   [0]['type']   field type
  1417.          *   [0]['len']    field length
  1418.          *   [0]['flags']  field flags
  1419.          *
  1420.          * - mode is MDB_TABLEINFO_ORDER
  1421.          * $result[]:
  1422.          *   ['num_fields'] number of metadata records
  1423.          *   [0]['table']  table name
  1424.          *   [0]['name']   field name
  1425.          *   [0]['type']   field type
  1426.          *   [0]['len']    field length
  1427.          *   [0]['flags']  field flags
  1428.          *   ['order'][field name]  index of field named "field name"
  1429.          *   The last one is used, if you have a field name, but no index.
  1430.          *   Test:  if (isset($result['meta']['myfield'])) { ...
  1431.          *
  1432.          * - mode is MDB_TABLEINFO_ORDERTABLE
  1433.          *    the same as above. but additionally
  1434.          *   ['ordertable'][table name][field name] index of field
  1435.          *      named 'field name'
  1436.          *
  1437.          *      this is, because if you have fields from different
  1438.          *      tables with the same field name * they override each
  1439.          *      other with MDB_TABLEINFO_ORDER
  1440.          *
  1441.          *      you can combine MDB_TABLEINFO_ORDER and
  1442.          *      MDB_TABLEINFO_ORDERTABLE with MDB_TABLEINFO_ORDER |
  1443.          *      MDB_TABLEINFO_ORDERTABLE * or with MDB_TABLEINFO_FULL
  1444.          */
  1445.  
  1446.         // if $result is a string, then we want information about a
  1447.         // table without a resultset
  1448.         if (is_string($result)) {
  1449.             $id = @mysql_list_fields($this->database_name,
  1450.                 $result, $this->connection);
  1451.             if (empty($id)) {
  1452.                 return($this->mysqlRaiseError());
  1453.             }
  1454.         } else { // else we want information about a resultset
  1455.             $id = $result;
  1456.             if (empty($id)) {
  1457.                 return($this->mysqlRaiseError());
  1458.             }
  1459.         }
  1460.  
  1461.         $count = @mysql_num_fields($id);
  1462.  
  1463.         // made this IF due to performance (one if is faster than $count if's)
  1464.         if (empty($mode)) {
  1465.             for ($i = 0; $i<$count; $i++) {
  1466.                 $res[$i]['table'] = @mysql_field_table ($id, $i);
  1467.                 $res[$i]['name'] = @mysql_field_name  ($id, $i);
  1468.                 $res[$i]['type'] = @mysql_field_type  ($id, $i);
  1469.                 $res[$i]['len']  = @mysql_field_len   ($id, $i);
  1470.                 $res[$i]['flags'] = @mysql_field_flags ($id, $i);
  1471.             }
  1472.         } else { // full
  1473.             $res['num_fields'] = $count;
  1474.  
  1475.             for ($i = 0; $i<$count; $i++) {
  1476.                 $res[$i]['table'] = @mysql_field_table ($id, $i);
  1477.                 $res[$i]['name'] = @mysql_field_name  ($id, $i);
  1478.                 $res[$i]['type'] = @mysql_field_type  ($id, $i);
  1479.                 $res[$i]['len']  = @mysql_field_len   ($id, $i);
  1480.                 $res[$i]['flags'] = @mysql_field_flags ($id, $i);
  1481.                 if ($mode & MDB_TABLEINFO_ORDER) {
  1482.                     $res['order'][$res[$i]['name']] = $i;
  1483.                 }
  1484.                 if ($mode & MDB_TABLEINFO_ORDERTABLE) {
  1485.                     $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
  1486.                 }
  1487.             }
  1488.         }
  1489.  
  1490.         // free the result only if we were called on a table
  1491.         if (is_string($result)) {
  1492.             @mysql_free_result($id);
  1493.         }
  1494.         return($res);
  1495.     }
  1496. }
  1497.  
  1498. ?>